﻿namespace Engine.Shape
{
    public struct Vector3Int
    {
        #region Public Constructors

        public Vector3Int(int x, int y, int z)
            : this()
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }

        #endregion Public Constructors

        #region Public Properties

        public static Vector3Int Zero { get { return new Vector3Int(0, 0, 0); } }
        public int X { get; set; }
        public int Y { get; set; }
        public int Z { get; set; }

        #endregion Public Properties

        #region Public Methods

        public static Vector3Int operator -(Vector3Int a, Vector3Int b)
        {
            return new Vector3Int(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
        }

        public static bool operator !=(Vector3Int a, Vector3Int b)
        {
            return !Vector3Int.Equals(a, b);
        }

        public static Vector3Int operator *(Vector3Int v, int i)
        {
            return new Vector3Int(v.X * i, v.Y * i, v.Z * i);
        }

        public static Vector3Int operator +(Vector3Int a, Vector3Int b)
        {
            return new Vector3Int(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
        }

        public static bool operator ==(Vector3Int a, Vector3Int b)
        {
            return Vector3Int.Equals(a, b);
        }

        /// <summary>
        /// Performs a coordinate transformation using the given <see cref="SharpDX.Matrix"/>.
        /// </summary>
        /// <param name="coordinate">The coordinate vector to transform.</param>
        /// <param name="transform">The transformation <see cref="SharpDX.Matrix"/>.</param>
        /// <returns>The transformed coordinates.</returns>
        /// <remarks>
        /// A coordinate transform performs the transformation with the assumption that the w component
        /// is one. The four dimensional vector obtained from the transformation operation has each
        /// component in the vector divided by the w component. This forces the wcomponent to be one and
        /// therefore makes the vector homogeneous. The homogeneous vector is often prefered when working
        /// with coordinates as the w component can safely be ignored.
        /// </remarks>
        public static Vector3Int TransformCoordinate(Vector3Int coordinate, SharpDX.Matrix transform)
        {
            Vector3Int result;
            TransformCoordinate(ref coordinate, ref transform, out result);
            return result;
        }

        /// <summary>
        /// Performs a coordinate transformation using the given <see cref="SharpDX.Matrix"/>.
        /// </summary>
        /// <param name="coordinate">The coordinate vector to transform.</param>
        /// <param name="transform">The transformation <see cref="SharpDX.Matrix"/>.</param>
        /// <param name="result">When the method completes, contains the transformed coordinates.</param>
        /// <remarks>
        /// A coordinate transform performs the transformation with the assumption that the w component
        /// is one. The four dimensional vector obtained from the transformation operation has each
        /// component in the vector divided by the w component. This forces the wcomponent to be one and
        /// therefore makes the vector homogeneous. The homogeneous vector is often prefered when working
        /// with coordinates as the w component can safely be ignored.
        /// </remarks>
        public static void TransformCoordinate(ref Vector3Int coordinate, ref SharpDX.Matrix transform, out Vector3Int result)
        {
            Vector4Int vector = new Vector4Int();
            vector.X = (int)((coordinate.X * transform.M11) + (coordinate.Y * transform.M21) + (coordinate.Z * transform.M31) + transform.M41);
            vector.Y = (int)((coordinate.X * transform.M12) + (coordinate.Y * transform.M22) + (coordinate.Z * transform.M32) + transform.M42);
            vector.Z = (int)((coordinate.X * transform.M13) + (coordinate.Y * transform.M23) + (coordinate.Z * transform.M33) + transform.M43);
            vector.W = (int)(1f / (float)((coordinate.X * transform.M14) + (coordinate.Y * transform.M24) + (coordinate.Z * transform.M34) + transform.M44));

            result = new Vector3Int(vector.X * vector.W, vector.Y * vector.W, vector.Z * vector.W);
        }

        #endregion Public Methods
    }
}